﻿#include "WebSocketClient.h"
#include <QNetworkRequest>
#include <iostream>

WebSocketClient::WebSocketClient()
    : m_bCloseByHand(false),
      m_webSocketState(stateNone),
      m_nHeartbeatTimer(5000),
      m_nReconnectHeartbatTimerCount(3),
      m_nReconnectTimer(5000),
      m_nDisconnectReconnectCount(3),
      m_nHeartbeatFailedCount(0),
      m_nReconnectFailedCount(0),
      m_strURL("ws://127.0.0.1:8088"),
      m_strSecWebsocketProtocol(tr("websocket")),
      m_strHeartbeatText(tr("heart beat message."))
{
  connect(&m_websocket, &QWebSocket::connected, this, &WebSocketClient::onConnected);
  connect(&m_websocket, SIGNAL(disconnected()), this, SLOT(onDisconnected()));
  connect(&m_websocket, SIGNAL(textMessageReceived(QString)), this,
          SLOT(onTextMessageReceived(QString)));
  connect(&m_timerHeartbeat, SIGNAL(timeout()), this, SLOT(onSendHeartbeatText()));
  connect(&m_timerReconnect, SIGNAL(timeout()), this, SLOT(onReconnect()));
}

WebSocketClient::~WebSocketClient()
{
  if (disconnected != m_webSocketState)
  {
    disconnect();
  }
}

void WebSocketClient::run()
{
  while (true)
  {
    if (m_webSocketState == connected)
    {
      m_mutex.lock();
      if (m_sendTextLinkedList.size())
      {
        QString strVal = *m_sendTextLinkedList.begin();
        if (m_websocket.sendTextMessage(strVal) == strVal.toLocal8Bit().length())
        {
          m_sendTextLinkedList.erase(m_sendTextLinkedList.begin());
        }
        m_mutex.unlock();
      }
      else
      {
        //当没有数据时，睡眠，否则cpu会过高
        QThread::msleep(20);
        m_mutex.unlock();
      }
    }
    else if (m_bCloseByHand)
    {
      break;
    }
  }
}

bool WebSocketClient::startConnect()
{
  bool bRet = false;

  // 如果URL地址 或者 特定的协议头为空 返回false
  if (!m_strURL.isEmpty() && !m_strSecWebsocketProtocol.isEmpty())
  {
    if (!isRunning())
    {
      start();
    }
    QNetworkRequest request;
    request.setUrl(QUrl(m_strURL));
    QByteArray byteHeader = "Protocol";
    request.setRawHeader(byteHeader, m_strSecWebsocketProtocol.toLocal8Bit());
    m_websocket.open(request);
    bRet = true;
  }

  return bRet;
}

void WebSocketClient::disconnect()
{
  m_bCloseByHand = true;
  m_websocket.close();
  m_timerHeartbeat.stop();
  m_timerReconnect.stop();
}

void WebSocketClient::setConnectUrl(QString val)
{
  m_strURL = val;
}

bool WebSocketClient::addSendText(QString val)
{
  bool bRet = false;
  if (m_webSocketState == disconnected || m_webSocketState == stateNone)
  {
    bRet = false;
  }
  else
  {
    m_mutex.lock();
    m_sendTextLinkedList.push_back(val);
    m_mutex.unlock();
    bRet = true;
  }
  return bRet;
}

void WebSocketClient::setSecWebSocketProtocolHeader(QString val)
{
  m_strSecWebsocketProtocol = val;
}

void WebSocketClient::setHeartbeatTimer(int val)
{
  if (val > 5000)
  {
    m_nHeartbeatTimer = val;
  }
}

void WebSocketClient::setReconnetHeartbeatTimerCount(int val)
{
  if (val > 3)
  {
    m_nReconnectHeartbatTimerCount = val;
  }
}

void WebSocketClient::setReconnectTimer(int val)
{
  if (val > 5000)
  {
    m_nReconnectTimer = val;
  }
}

void WebSocketClient::setDisconnectReconnectCount(int val)
{
  if (val > 3)
  {
    m_nDisconnectReconnectCount = val;
  }
}

WebSocketClient::webSocketState WebSocketClient::getCurrentState()
{
  return m_webSocketState;
}

void WebSocketClient::onConnected()
{
  // 如果是重连成功 停止重连的定时Timer
  if (m_webSocketState == reconnecting)
  {
    m_timerReconnect.stop();
  }
  m_webSocketState = connected;
  m_timerHeartbeat.start(m_nHeartbeatTimer);
  m_nReconnectFailedCount = 0;
  m_nHeartbeatFailedCount = 0;
  std::cout << "Connected" << std::endl;
}

void WebSocketClient::onDisconnected()
{
  // 如果不是手动关闭 则需要重连
  if (!m_bCloseByHand)
  {
    m_timerHeartbeat.stop();
    m_timerReconnect.start(m_nReconnectTimer);
    m_webSocketState = reconnecting;
  }
}

void WebSocketClient::onTextMessageReceived(const QString& val)
{
  //收到网页后端发来的内容，处理内容
  std::cout << val.toStdString() << std::endl;
}

void WebSocketClient::onSendHeartbeatText()
{
  // 加锁 保证websocket 只在同一时间发送一条数据
  m_mutex.lock();
  int nSendByte = m_websocket.sendTextMessage(m_strHeartbeatText);
  m_mutex.unlock();
  // 发送心跳失败
  if (nSendByte != m_strHeartbeatText.toLocal8Bit().length())
  {
    m_nHeartbeatFailedCount++;
    // 失败次数等于启动重连的次数 停止发送心跳 开启重连 更新状态
    if (m_nHeartbeatFailedCount == m_nReconnectHeartbatTimerCount)
    {
      m_timerHeartbeat.stop();
      m_timerReconnect.start(m_nReconnectTimer);
      m_webSocketState = reconnecting;
    }
  }
}

void WebSocketClient::onReconnect()
{
  // close websocket
  m_websocket.close();
  //如果重连次数已到 不再重连 处于断开状态
  if (m_nReconnectFailedCount == m_nReconnectHeartbatTimerCount)
  {
    m_webSocketState = disconnected;
    m_timerReconnect.stop();
  }
  else  // 开始连接并计数
  {
    startConnect();
    m_nReconnectFailedCount++;
  }
}